package com.treasure.mall.biz.service.core.community.impl;


import com.alibaba.fastjson.JSONArray;
import com.treasure.mall.biz.base.AbstractSearchableCrudService;
import com.treasure.mall.biz.base.SpecificationAndSort;
import com.treasure.mall.biz.dto.BaseSaveDTO;
import com.treasure.mall.biz.dto.BaseSearchDTO;
import com.treasure.mall.biz.dto.community.CommunityArticleSaveDTO;
import com.treasure.mall.biz.dto.community.CommunityArticleSearchCondition;
import com.treasure.mall.biz.entity.community.*;
import com.treasure.mall.biz.entity.user.UserPO;
import com.treasure.mall.biz.entity.user.UserPO_;
import com.treasure.mall.biz.repository.community.CommunityArticleLikeRepository;
import com.treasure.mall.biz.repository.community.CommunityArticleRepository;
import com.treasure.mall.biz.repository.community.CommunityVisitRepository;
import com.treasure.mall.biz.service.core.community.CommunityArticleService;
import com.treasure.mall.biz.service.core.community.CommunityCommentService;
import com.treasure.mall.biz.service.core.user.UserService;
import com.treasure.mall.zbq.common.base.ApiResult;
import com.treasure.mall.zbq.common.base.ResultCodeEnum;
import com.treasure.mall.zbq.common.exception.ApiException;
import com.treasure.mall.zbq.common.ienum.base.CodeDescEnumHelper;
import com.treasure.mall.zbq.common.ienum.community.CommunityEnums;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

/**
 * author : guomw
 * date : 2020
 */
@Service
@Slf4j
public class CommunityArticleServiceImpl extends AbstractSearchableCrudService<CommunityArticlePO, Long> implements CommunityArticleService {
    @Autowired
    private CommunityCommentService commentsService;
    @Autowired
    private CommunityArticleLikeRepository articleLikeRepository;
    @Autowired
    private CommunityVisitRepository visitRepository;
    @Autowired
    private UserService userService;


    private CommunityArticleRepository communityArticleRepository;

    protected CommunityArticleServiceImpl(CommunityArticleRepository repository) {
        super(repository);
        this.communityArticleRepository = repository;
    }

    @Override
    protected SpecificationAndSort<CommunityArticlePO> specificationAndSort(BaseSearchDTO searchDTO) {
        CommunityArticleSearchCondition condition = (CommunityArticleSearchCondition) searchDTO;

        Specification<CommunityArticlePO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            predicates.add(cb.equal(root.get(CommunityArticlePO_.deleted), false));

            if (StringUtils.isNotBlank(condition.getKeyword())) {
                predicates.add(cb.or(
                        cb.like(root.get(CommunityArticlePO_.title), likeAll(condition.getKeyword())),
                        cb.like(root.get(CommunityArticlePO_.description), likeAll(condition.getKeyword()))
                ));
            }

            if (condition.getType() > -1) {
                CommunityEnums.ContentType type = CodeDescEnumHelper.getEnumTypeByCode(CommunityEnums.ContentType.class, condition.getType());
                predicates.add(cb.equal(root.get(CommunityArticlePO_.contentType), type));
            }
            if (condition.getUserId() > 0) {
                predicates.add(cb.equal(root.get(CommunityArticlePO_.author).get(UserPO_.userId), condition.getUserId()));
            }

            if (StringUtils.isNotBlank(condition.getMobile())) {
                predicates.add(cb.equal(root.get(CommunityArticlePO_.author).get(UserPO_.mobile), condition.getMobile()));
            }
            if (StringUtils.isNotBlank(condition.getNickName())) {
                predicates.add(cb.like(root.get(CommunityArticlePO_.author).get(UserPO_.nickName), likeAll(condition.getKeyword())));
            }

            if (condition.getStatus() > -1) {
                CommunityEnums.AuditStatus auditStatus = CodeDescEnumHelper.getEnumTypeByCode(CommunityEnums.AuditStatus.class, condition.getStatus());
                predicates.add(cb.equal(root.get(CommunityArticlePO_.auditStatus), auditStatus));
            }

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");

        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    public CommunityArticlePO save(BaseSaveDTO saveDTO) {
        CommunityArticleSaveDTO dto = (CommunityArticleSaveDTO) saveDTO;

        return save(convertToEntity(dto));
    }

    @Override
    @Transactional
    public CommunityCommentPO comment(Long articleId, UserPO userPO, String content) {
        CommunityArticlePO articlePO = findById(articleId);
        if (articlePO == null || articlePO.isDeleted()) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "当前内容不存在或者内容已被删除"));
        }

        CommunityCommentPO po = commentsService.comment(0, 0, articlePO, content, userPO);

        //修改评论数量
        communityArticleRepository.updateCommentCount(articleId, 1);

        return po;
    }

    @Override
    @Transactional
    public boolean likeToggle(Long articleId, UserPO userPO) {
        CommunityArticlePO articlePO = findById(articleId);
        if (articlePO == null || articlePO.isDeleted()) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "当前内容不存在或者内容已被删除"));
        }

        CommunityArticleLikePO po = articleLikeRepository.findByArticlePO_IdAndUser_UserId(articleId, userPO.getUserId());

        if (po == null) {
            po = new CommunityArticleLikePO();

            po.setArticlePO(articlePO);
            po.setUser(userPO);
            articleLikeRepository.save(po);

            communityArticleRepository.updateLikeCount(articleId, 1);

            return true;
        } else {
            articleLikeRepository.deleteById(po.getId());

            communityArticleRepository.updateLikeCount(articleId, -1);

            return false;
        }
    }

    @Override
    public long likeCount(Long userId) {
        return articleLikeRepository.countByArticlePO_Id(userId);
    }

    @Override
    public long countByUser(Long userId) {
        return communityArticleRepository.countByAuthor_UserIdAndDeletedIsFalse(userId);
    }

    @Override
    public long countByUserAudit(Long userId) {
        return communityArticleRepository.countByAuthor_UserIdAndAuditStatusAndDeletedIsFalse(userId, CommunityEnums.AuditStatus.WAIT);
    }

    @Override
    public Page<CommunityArticleLikePO> likes(Long userId, int pageIndex, int pageSize) {
        return articleLikeRepository.findByUser_UserId(userId, PageRequest.of(pageIndex - 1, pageSize));
    }

    @Override
    public boolean isUserLiked(Long articleId, Long userId) {
        return articleLikeRepository.existsByArticlePO_IdAndUser_UserId(articleId, userId);
    }

    @Override
    public void delete(Long userId, Long articleId) {
        CommunityArticlePO articlePO = findById(articleId);
        if (!articlePO.getAuthor().getUserId().equals(userId)) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "你不是该内容的发布者，无法删除"));
        }
        articlePO.setDeleted(true);

        save(articlePO);
    }

    private CommunityArticlePO convertToEntity(CommunityArticleSaveDTO dto) {
        if (dto.getUser() == null) {
            throw new ApiException("用户不存在");
        }
        CommunityArticlePO po;
        if (dto.getArticleId() > 0) {
            po = findById(dto.getArticleId());
            if (po.getAuditStatus() != CommunityEnums.AuditStatus.SUCCESS) {
                throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "该内容已审核通过，无法编辑"));
            }
            if (!po.getAuthor().getId().equals(dto.getUser().getId())) {
                throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "你不是该内容的发布者，无法编辑"));
            }
        } else {
            po = new CommunityArticlePO();
            po.setAuthor(dto.getUser());
        }

        po.setAuditStatus(CommunityEnums.AuditStatus.WAIT);

        po.setContentType(dto.getContentType());
        po.setDescription(dto.getDescription());
        po.setTitle(dto.getTitle());
        if (StringUtils.isNotBlank(dto.getCoverUrl())) {
            po.setMainPic(dto.getCoverUrl());
        }
        if (dto.getContentType().getCode().equals(CommunityEnums.ContentType.IMAGE_TEXT.getCode())) {
            if (dto.getPicList() == null || dto.getPicList().size() == 0) {
                throw new ApiException("请上传图片");
            }
            po.setPicList(JSONArray.toJSONString(dto.getPicList()));
            if (StringUtils.isEmpty(dto.getCoverUrl())) {
                po.setMainPic(dto.getPicList().get(0));
            }
        } else {
            if (StringUtils.isEmpty(dto.getVideoUrl())) {
                throw new ApiException("请上传视频");
            }
            po.setVideoUrl(dto.getVideoUrl());
            if (StringUtils.isEmpty(dto.getCoverUrl())) {
                po.setMainPic(dto.getVideoUrl() + "?x-oss-process=video/snapshot,t_1000,m_fast,ar_auto");
            }
        }
        return po;
    }

    /**
     * 添加访问记录
     *
     * @param visitUser
     * @param articleId
     */
    @Override
    @Transactional
    public void modifyCommunityArticleVisit(UserPO visitUser, Long articleId) {
        CommunityVisitPO visitPO = new CommunityVisitPO();
        if (visitUser != null) {
            visitPO.setVisitUser(visitUser);//用户可能为空
        }
        visitPO.setArticle(this.findById(articleId));
        visitRepository.save(visitPO);
        communityArticleRepository.updateVisitCount(articleId, 1);
    }

    /**
     * 修改文章审核状态
     *
     * @param id
     * @param auditStatus
     * @param reason
     */
    @Override
    public void modifyCommunityArticleAuditStatus(Long id, CommunityEnums.AuditStatus auditStatus, String reason) {
        CommunityArticlePO po = findById(id);
        if (po == null) {
            throw new ApiException("文章不存在或已删除");
        }
        if (po.getAuditStatus() == CommunityEnums.AuditStatus.SUCCESS) {
            throw new ApiException("该内容已审核通过，无法编辑");
        }
        communityArticleRepository.modifyCommunityArticleAuditStatus(id, auditStatus, reason);
    }

}
